package com.xh3140.android.widget.dialog.utils;

import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.annotation.Size;

import java.lang.reflect.InvocationTargetException;

@SuppressWarnings("unused")
public final class LayoutParamsBuilder {
    private final static int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT;
    private final static int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;

    private final Class<? extends ViewGroup.LayoutParams> clazz;
    private final ViewGroup.LayoutParams params;

    public static LayoutParamsBuilder ofWW(@NonNull Class<? extends ViewGroup.LayoutParams> cls) {
        return new LayoutParamsBuilder(cls, WRAP_CONTENT, WRAP_CONTENT);
    }

    public static LayoutParamsBuilder ofMW(@NonNull Class<? extends ViewGroup.LayoutParams> cls) {
        return new LayoutParamsBuilder(cls, MATCH_PARENT, WRAP_CONTENT);
    }

    public static LayoutParamsBuilder ofWM(@NonNull Class<? extends ViewGroup.LayoutParams> cls) {
        return new LayoutParamsBuilder(cls, WRAP_CONTENT, MATCH_PARENT);
    }

    public static LayoutParamsBuilder ofMM(@NonNull Class<? extends ViewGroup.LayoutParams> cls) {
        return new LayoutParamsBuilder(cls, MATCH_PARENT, MATCH_PARENT);
    }

    public LayoutParamsBuilder(@NonNull Class<? extends ViewGroup.LayoutParams> cls) {
        this(cls, WRAP_CONTENT, WRAP_CONTENT);
    }

    public LayoutParamsBuilder(@NonNull Class<? extends ViewGroup.LayoutParams> cls, int width, int height) {
        clazz = cls;
        try {
            params = clazz.getConstructor(int.class, int.class).newInstance(width, height);
        } catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
            e.printStackTrace();
            throw new RuntimeException("Class<? extends ViewGroup.LayoutParams> Constructor error.");
        }
    }

    public ViewGroup.LayoutParams build() {
        return params;
    }

    public LayoutParamsBuilder setWidth(int width) {
        params.width = width;
        return this;
    }

    public LayoutParamsBuilder setHeight(int height) {
        params.height = height;
        return this;
    }

    public LayoutParamsBuilder setWeight(float weight) {
        try {
            clazz.getField("weight").set(params, weight);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return this;
    }

    public LayoutParamsBuilder setGravity(int gravity) {
        try {
            clazz.getField("gravity").set(params, gravity);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return this;
    }

    public LayoutParamsBuilder setMarginLeft(@Px int leftMargin) {
        if (params instanceof ViewGroup.MarginLayoutParams) {
            ((ViewGroup.MarginLayoutParams) params).leftMargin = leftMargin;
        }
        return this;
    }

    public LayoutParamsBuilder setMarginTop(@Px int topMargin) {
        if (params instanceof ViewGroup.MarginLayoutParams) {
            ((ViewGroup.MarginLayoutParams) params).topMargin = topMargin;
        }
        return this;
    }

    public LayoutParamsBuilder setMarginRight(@Px int rightMargin) {
        if (params instanceof ViewGroup.MarginLayoutParams) {
            ((ViewGroup.MarginLayoutParams) params).rightMargin = rightMargin;
        }
        return this;
    }

    public LayoutParamsBuilder setMarginBottom(@Px int bottomMargin) {
        if (params instanceof ViewGroup.MarginLayoutParams) {
            ((ViewGroup.MarginLayoutParams) params).bottomMargin = bottomMargin;
        }
        return this;
    }

    public LayoutParamsBuilder setMarginStart(@Px int startMargin) {
        if (params instanceof ViewGroup.MarginLayoutParams) {
            ((ViewGroup.MarginLayoutParams) params).setMarginStart(startMargin);
        }
        return this;
    }

    public LayoutParamsBuilder setMarginEnd(@Px int endMargin) {
        if (params instanceof ViewGroup.MarginLayoutParams) {
            ((ViewGroup.MarginLayoutParams) params).setMarginEnd(endMargin);
        }
        return this;
    }

    public LayoutParamsBuilder setMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) {
        if (params instanceof ViewGroup.MarginLayoutParams) {
            ((ViewGroup.MarginLayoutParams) params).leftMargin = left;
            ((ViewGroup.MarginLayoutParams) params).topMargin = top;
            ((ViewGroup.MarginLayoutParams) params).rightMargin = right;
            ((ViewGroup.MarginLayoutParams) params).bottomMargin = bottom;
        }
        return this;
    }

    public LayoutParamsBuilder setMarginsRelative(@Px int start, @Px int top, @Px int end, @Px int bottom) {
        if (params instanceof ViewGroup.MarginLayoutParams) {
            ((ViewGroup.MarginLayoutParams) params).setMarginStart(start);
            ((ViewGroup.MarginLayoutParams) params).topMargin = top;
            ((ViewGroup.MarginLayoutParams) params).setMarginEnd(end);
            ((ViewGroup.MarginLayoutParams) params).bottomMargin = bottom;
        }
        return this;
    }

    public LayoutParamsBuilder setMargins(@Nullable @Size(4) int[] margins) {
        if (margins != null && params instanceof ViewGroup.MarginLayoutParams) {
            ((ViewGroup.MarginLayoutParams) params).leftMargin = margins[0];
            ((ViewGroup.MarginLayoutParams) params).topMargin = margins[1];
            ((ViewGroup.MarginLayoutParams) params).rightMargin = margins[2];
            ((ViewGroup.MarginLayoutParams) params).bottomMargin = margins[3];
        }
        return this;
    }

    public LayoutParamsBuilder setMarginsRelative(@Nullable @Size(4) int[] margins) {
        if (margins != null && params instanceof ViewGroup.MarginLayoutParams) {
            ((ViewGroup.MarginLayoutParams) params).setMarginStart(margins[0]);
            ((ViewGroup.MarginLayoutParams) params).topMargin = margins[1];
            ((ViewGroup.MarginLayoutParams) params).setMarginEnd(margins[2]);
            ((ViewGroup.MarginLayoutParams) params).bottomMargin = margins[3];
        }
        return this;
    }
}
